/*
 * mdb - A memory database
 * author	: calvin
 * email	: calvinwilliams@163.com
 *
 * Licensed under the LGPL v2.1, see the file LICENSE in base directory.
 */

#ifndef _H_MDB_
#define _H_MDB_

#ifdef __cplusplus
extern "C" {
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
#include <stdarg.h>
#include <inttypes.h>
#include <pthread.h>
#include <sys/time.h>
#include <linux/limits.h>

#ifndef MAX
#define MAX(_a_,_b_) ( (_a_) > (_b_) ? (_a_) : (_b_) )
#endif

#ifndef MIN
#define MIN(_a_,_b_) ( (_a_) < (_b_) ? (_a_) : (_b_) )
#endif

#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif

#define sizeof0(_struct_name_,_struct_property_name_)		sizeof(((_struct_name_*)0)->_struct_property_name_)

#define MDB_DATABASE_NAME_MAX_LENGTH	64
#define MDB_TABLE_NAME_MAX_LENGTH	64
#define MDB_INDEX_NAME_MAX_LENGTH	64

#define MDB_ERROR_ALLOC					-11
#define MDB_INFO_SUPPORT_IN_FUTURE			101
#define MDB_ERROR_INTERNATIONAL				-102
#define MDB_ERROR_FIELDS_END_PATAMETER_INVALID		-201
#define MDB_ERROR_TOO_MANY_FIELDS			-202
#define MDB_ERROR_AUTOINCREMENT_FIELD_SIZE_INVALID	-203
#define MDB_ERROR_DATABASE_NAME_TOO_LONG		-301
#define MDB_ERROR_TABLE_NAME_TOO_LONG			-401
#define MDB_ERROR_TABLE_DUPLICATED			-411
#define MDB_ERROR_TABLE_NOT_FOUND			-412
#define MDB_ERROR_INDEX_NAME_TOO_LONG			-501
#define MDB_ERROR_INDEX_DUPLICATED			-511
#define MDB_ERROR_INDEX_NOT_FOUND			-512
#define MDB_INFO_SQL_NOT_FOUND				400
#define MDB_ERROR_RECORD_NO_INDEX			-601
#define MDB_ERROR_RECORD_DATAPAGE_IS_FULL		-601
#define MDB_ERROR_IN_TRANSACTION			-701
#define MDB_ERROR_MUTILDATABASE_IN_TRANSACTION		-702

#define MDB_UNIQUEINDEX			1
#define MDB_INDEX			0

#define MDBFIELD_NONE			NULL

#define MDBFIELD(_struct_name_,_struct_property_name_)		#_struct_property_name_ , (int)offsetof(_struct_name_,_struct_property_name_) , sizeof0(_struct_name_,_struct_property_name_)

struct MemDatabase;
struct MemTable;
struct MemIndex;

/*
 * Database
 */

/*
void MDBSetDataFilesPath( char *path );
*/

struct MemDatabase *MDBCreateDatabase( char *db_name );
int MDBDropDatabase( struct MemDatabase *db );

/*
 * Table
 */

struct MemTable *MDBCreateTable( struct MemDatabase *db , char *table_name , size_t record_size );
int MDBDropTable( struct MemDatabase *db , char *table_name );
int MDBDropTableDirectly( struct MemDatabase *db , struct MemTable *table );
struct MemTable *MDBQueryTable( struct MemDatabase *db , char *table_name );

int MDBSetAutoIncrementField( struct MemTable *table , char *field_name,int field_offset,size_t field_size );

/*
 * Index
 */

/*
CREATE INDEX index_name ON table_name ( field1_name , field2_name ) ;
|
MDBCreateIndex( table
	, MDB_UNIQUEINDEX
	, MDBFIELD(struct_name,struct_variable1_name)
	, MDBFIELD(struct_name,struct_variable2_name)
	, ...
	, MDBFIELD_NONE
	);
*/
struct MemIndex *MDBCreateIndex( struct MemTable *table , char *index_name , unsigned char is_unique , ... );
int MDBDropIndex( struct MemTable *table , char *index_name );
int MDBDropIndexDirectly( struct MemTable *table , struct MemIndex *index );
struct MemIndex *MDBQueryIndex( struct MemTable *table , char *index_name );

/*
 * Insert records
 */

/*
INSERT INTO table_name ( field1_value , field2_value ) ;
|
MDBInsert( table
	, & insert_record
	);
*/
int MDBInsert( struct MemTable *table , void *insert_record );

/*
INSERT INTO table_name ( field1_value , field2_value ) , ( field1_value , field2_value ) ;
|
MDBInsertBatch( table
	, insert_record_array , insert_record_array_count
	);
*/
int MDBInsertBatch( struct MemTable *table , void *insert_record_array , size_t insert_record_array_count );

/*
 * Update records
 */

/*
UPDATE table_name SET field1_name=field1_value,field2_name=field2_value WHERE field3_name=field3_value AND field4_name=field4_value ;
|
MDBUpdate( table
	, & set_record
	, MDBFIELD(struct_name,struct_variable1_name)
	, MDBFIELD(struct_name,struct_variable2_name)
	, ...
	, MDBFIELD_NONE
	, & where_record
	, MDBFIELD(struct_name,struct_variable3_name)
	, MDBFIELD(struct_name,struct_variable4_name)
	, ...
	, MDBFIELD_NONE
	);
*/
int MDBUpdate( struct MemTable *table , void *set_record , ... );

/*
 * Delete records
 */

/*
DELETE FROM table_name field3_name=field3_value AND field4_name=field4_value ;
|
MDBDelete( table
	, & where_record
	, MDBFIELD(struct_name,struct_variable3_name)
	, MDBFIELD(struct_name,struct_variable4_name)
	, ...
	, MDBFIELD_NONE
	);
*/
int MDBDelete( struct MemTable *table , void *where_record , ... );

/*
 * Select records
 */

/*
SELECT field1,field2 FROM table_name WHERE field3_name=field3_value AND field4_name=field4_value ;
|
MDBSelect( table
	, & select_record
	, MDBFIELD(struct_name,struct_variable1_name)
	, MDBFIELD(struct_name,struct_variable2_name)
	, ...
	, MDBFIELD_NONE
	, & where_record
	, MDBFIELD(struct_name,struct_variable3_name)
	, MDBFIELD(struct_name,struct_variable4_name)
	, ...
	, MDBFIELD_NONE
	);
*/
int MDBSelect( struct MemTable *table , void *select_record , ... );

/*
SELECT field1,field2 FROM table_name WHERE field3_name=field3_value AND field4_name=field4_value ;
|
MDBSelectBatch( table
	, & select_record_array , select_record_array_size , & select_record_array_count
	, MDBFIELD(struct_name,struct_variable1_name)
	, MDBFIELD(struct_name,struct_variable2_name)
	, ...
	, MDBFIELD_NONE
	, & where_record
	, MDBFIELD(struct_name,struct_variable3_name)
	, MDBFIELD(struct_name,struct_variable4_name)
	, ...
	, MDBFIELD_NONE
	);
*/
int MDBSelectBatch( struct MemTable *table , void *select_record_array , size_t select_record_array_size , size_t *select_record_array_count , ... );

int MDBGetLastError();

/*
 * Transaction
 */

int MDBBeginTransaction( struct MemDatabase *db );
int MDBCommitTransaction( struct MemDatabase *db );
int MDBRollbackTransaction( struct MemDatabase *db );

#define MDBBeginWork MDBBeginTransaction
#define MDBCommit MDBCommitTransaction
#define MDBRollback MDBRollbackTransaction

#ifdef __cplusplus
}
#endif

#endif

